/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is Forte for Java, Community Edition. The Initial * Developer of the Original Code is Sun Microsystems, Inc. Portions * Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved. */ package org.openide.src; import java.io.IOException; import java.io.Reader; import java.io.PrintWriter; import java.util.Enumeration; import java.util.Vector; import java.text.MessageFormat; import org.openide.util.Task; /** Describes an entire Java source file. * Note that there is no standard in-memory implementation of this element; * every user of the class is expected to have a reasonable * implementation according to where the source file resides. * <p>The source element should be parsed in the background using * {@link #prepare} before any attempts are made to access its properties * to read or to write, or to call {@link #print}; * otherwise such accesses will block until the parse is finished. * @author Petr Hamernik, Jaroslav Tulach */ public final class SourceElement extends Element { /** Status when the source element is not yet prepared. */ public static final int STATUS_NOT = 0; /** Status when the source element contains unrecoverable errors. */ public static final int STATUS_ERROR = 1; /** Status when the source element contains minor errors. */ public static final int STATUS_PARTIAL = 2; /** Status when the source element has been parsed and is error-free. */ public static final int STATUS_OK = 3; static final long serialVersionUID =-1439690719608070114L; /** Create a new source element. * @param impl the pluggable implementation */ public SourceElement(Impl impl) { super (impl); } /** @return implementation for the source */ final Impl getSourceImpl () { return (Impl)impl; } /** Get the parsing status of the element. * This is a non-blocking operation. * @return one of {@link #STATUS_NOT}, {@link #STATUS_ERROR}, {@link #STATUS_PARTIAL}, or {@link #STATUS_OK} */ public int getStatus () { return getSourceImpl ().getStatus (); } /** Begin parsing this source element. * This method is non-blocking; it only returns * a task that can be used to control the ongoing parse. * Initially the {@link #getStatus} should be {@link #STATUS_NOT}, and change * to one of the other three when parsing is complete, according to whether * or not errors were encountered, and their severity. * * @return a task to control the preparation of the element */ public Task prepare () { return getSourceImpl ().prepare (); } // =========================== package section ============================ /** Set the package of this source file. * @param id the package name, or <code>null</code> to use the default package * @exception SourceException if the operation cannot proceed */ public void setPackage (Identifier id) throws SourceException { getSourceImpl ().setPackage (id); } /** Get the package of this source file. * @return the package name, or <code>null</code> if this source file is in the default package */ public Identifier getPackage () { return getSourceImpl ().getPackage (); } // =========================== imports section ============================ /** Get all imports. * * @return the imports */ public Import[] getImports() { return getSourceImpl ().getImports (); } /** Set all imports. * The old imports will be replaced. * @param imprt the new imports * @exception SourceException if the operation cannot proceed */ public void setImports(Import[] imprt) throws SourceException { getSourceImpl ().changeImports (imprt, Impl.SET); } /** Add an import. * @param el the import to add * @exception SourceException if the operation cannot proceed */ public void addImport (Import el) throws SourceException { getSourceImpl ().changeImports ( new Import[] { el }, Impl.ADD ); } /** Add some imports. * @param els the imports to add * @exception SourceException if the operation cannot proceed */ public void addImports (final Import[] els) throws SourceException { getSourceImpl ().changeImports (els, Impl.ADD); } /** Remove an import. * @param el the import to remove * @exception SourceException if the operation cannot proceed */ public void removeImport (Import el) throws SourceException { getSourceImpl ().changeImports ( new Import[] { el }, Impl.REMOVE ); } /** Remove some imports. * @param els the imports to remove * @exception SourceException if the operation cannot proceed */ public void removeImports (final Import[] els) throws SourceException { getSourceImpl ().changeImports (els, Impl.REMOVE); } //================== Top-level classes ========================== /** Add a new top-level class. * @param el the top-level class to add * @throws SourceException if impossible */ public void addClass (ClassElement el) throws SourceException { if (getClass(el.getName()) != null) throwAddException("FMT_EXC_AddClassToSource", el); // NOI18N getSourceImpl ().changeClasses (new ClassElement[] { el }, Impl.ADD); } /** Add some new top-level classes. * @param el the top-level classes to add * @throws SourceException if impossible */ public void addClasses (final ClassElement[] els) throws SourceException { for (int i = 0; i < els.length; i++) { if (getClass(els[i].getName()) != null) throwAddException("FMT_EXC_AddClassToSource", els[i]); // NOI18N } getSourceImpl ().changeClasses (els, Impl.ADD); } /** This method just throws localized exception. It is used during * adding class element, which already exists in source. * @param formatKey The message format key to localized bundle. * @param element The element which can't be added * @exception SourceException is alway thrown from this method. */ private void throwAddException(String formatKey, ClassElement element) throws SourceException { MessageFormat format = new MessageFormat(ElementFormat.bundle.getString(formatKey)); String msg = format.format(new Object[] { element.getName().getName() }); throw new SourceException(msg); } /** Remove an top-level class. * @param el the top-level class to remove * @throws SourceException if impossible */ public void removeClass (ClassElement el) throws SourceException { getSourceImpl ().changeClasses (new ClassElement[] { el }, Impl.REMOVE); } /** Remove some top-level classes. * @param els the top-level classes to remove * @throws SourceException if impossible */ public void removeClasses (final ClassElement[] els) throws SourceException { getSourceImpl ().changeClasses (els, Impl.REMOVE); } /** Set the top-level classes. * The old ones will be replaced. * @param els the new top-level classes * @throws SourceException if impossible */ public void setClasses (ClassElement[] els) throws SourceException { getSourceImpl ().changeClasses (els, Impl.SET); } /** Get the top-level classes. * @return all top-level classes */ public ClassElement[] getClasses () { return getSourceImpl ().getClasses (); } /** Find a top-level class by name. * @param name the name to look for * @return the class, or <code>null</code> if it does not exist */ public ClassElement getClass (Identifier name) { return getSourceImpl ().getClass (name); } /** Get all classes recursively, both top-level and inner. * @return all classes */ public ClassElement[] getAllClasses () { return getSourceImpl ().getAllClasses (); } /* Prints the element into the element printer. * @param printer The element printer where to print to * @exception ElementPrinterInterruptException if printer cancel the printing */ public void print(ElementPrinter printer) throws ElementPrinterInterruptException { Identifier pack = getPackage(); if (pack != null) { printer.print("package "); // NOI18N printer.print(pack.getFullName()); printer.println(";"); // NOI18N printer.println(""); // NOI18N } Import[] imp = getImports(); for(int i = 0; i < imp.length; i++) { printer.print(imp[i].toString()); printer.println(";"); // NOI18N } if (imp.length > 0) printer.println(""); // NOI18N print(getClasses(), printer); } /** Lock the underlaing document to have exclusive access to it and could make changes * on this SourceElement. * * @param run the action to run */ public void runAtomic (Runnable run) { getSourceImpl ().runAtomic(run); } /** Executes given runnable in "user mode" does not allowing any modifications * to parts of text marked as guarded. The actions should be run as "atomic" so * either happen all at once or none at all (if a guarded block should be modified). * * @param run the action to run * @exception SourceException if a modification of guarded text occured * and that is why no changes to the document has been done. */ public void runAtomicAsUser (Runnable run) throws SourceException { getSourceImpl ().runAtomicAsUser(run); } /** Pluggable behaviour for source elements. * @see SourceElement */ public static interface Impl extends Element.Impl { /** Add some top-level classes. */ public static final int ADD = ClassElement.Impl.ADD; /** Remove some top-level classes. */ public static final int REMOVE = ClassElement.Impl.REMOVE; /** Set the top-classes. */ public static final int SET = ClassElement.Impl.SET; static final long serialVersionUID =-2181228658756563166L; /** Get the parsing status of the element. * This is a non-blocking operation. * @return one of {@link #STATUS_NOT}, {@link #STATUS_ERROR}, {@link #STATUS_PARTIAL}, or {@link #STATUS_OK} */ public int getStatus (); /** Begin parsing this source element. * This method is non-blocking; it only returns * a task that can be used to control the ongoing parse. * Initially the {@link #getStatus} should be {@link #STATUS_NOT}, and change * to one of the other three when parsing is complete, according to whether * or not errors were encountered, and their severity. * * @return a task to control the preparation of the element */ public Task prepare (); /** Set the package of this source file. * @param id the package name, or <code>null</code> to use the default package * @exception SourceException if the operation cannot proceed */ public void setPackage (Identifier id) throws SourceException; /** Get the package of this source file. * @return the package name, or <code>null</code> if this source file is in the default package */ public Identifier getPackage (); // =========================== imports section ============================ /** Get all imports. * * @return the imports */ public Import[] getImports(); /** Change the set of imports. * @param elems the imports to change * @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET} * @exception SourceException if the action cannot be handled */ public void changeImports (Import[] elems, int action) throws SourceException; /** Change the set of top-level classes. * @param elems the classes to change * @param action one of {@link #ADD}, {@link #REMOVE}, or {@link #SET} * @exception SourceException if the action cannot be handled */ public void changeClasses (ClassElement[] elems, int action) throws SourceException; /** Get all top-level classes. * @return the classes */ public ClassElement[] getClasses (); /** Find a top-level class by name. * @param name the name to look for * @return the class, or <code>null</code> if it does not exist */ public ClassElement getClass (Identifier name); /** Get all classes recursively, both top-level and inner. * @return all classes */ public ClassElement[] getAllClasses (); /** Lock the underlaing document to have exclusive access to it and could make changes * on this SourceElement. * * @param run the action to run */ public void runAtomic (Runnable run); /** Executes given runnable in "user mode" does not allowing any modifications * to parts of text marked as guarded. The actions should be run as "atomic" so * either happen all at once or none at all (if a guarded block should be modified). * * @param run the action to run * @exception SourceException if a modification of guarded text occured * and that is why no changes to the document has been done. */ public void runAtomicAsUser (Runnable run) throws SourceException; } } /* * Log * 20 src-jtulach1.19 1/12/00 Petr Hamernik i18n using perl script * (//NOI18N comments added) * 19 src-jtulach1.18 10/22/99 Ian Formanek NO SEMANTIC CHANGE - Sun * Microsystems Copyright in File Comment * 18 src-jtulach1.17 9/29/99 Petr Hamernik During adding elements * is tested if they are already added (fixed bugs #3130, #1706) * 17 src-jtulach1.16 9/13/99 Petr Hamernik runAsUser implemented * and used * 16 src-jtulach1.15 8/9/99 Ian Formanek Generated Serial Version * UID * 15 src-jtulach1.14 7/8/99 Petr Hamernik runAtomic methods added * 14 src-jtulach1.13 6/8/99 Ian Formanek ---- Package Change To * org.openide ---- * 13 src-jtulach1.12 5/12/99 Petr Hamernik Identifier * implementation updated * 12 src-jtulach1.11 4/14/99 Petr Hamernik fixed bug #1523 * 11 src-jtulach1.10 3/30/99 Jesse Glick [JavaDoc] * 10 src-jtulach1.9 3/30/99 Jan Jancura Bug in gatAllClasses() * 9 src-jtulach1.8 3/22/99 Petr Hamernik printing changed * 8 src-jtulach1.7 2/11/99 Petr Hamernik * 7 src-jtulach1.6 2/10/99 Jaroslav Tulach * 6 src-jtulach1.5 2/4/99 Petr Hamernik setting of extended file * attributes doesn't require FileLock * 5 src-jtulach1.4 1/27/99 Jaroslav Tulach xxxClasses, xxxImports * 4 src-jtulach1.3 1/19/99 Jaroslav Tulach * 3 src-jtulach1.2 1/19/99 Jaroslav Tulach * 2 src-jtulach1.1 1/18/99 David Simonek property constants added * 1 src-jtulach1.0 1/17/99 Jaroslav Tulach * $ */